home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpat2-1.000 / xpat2-1 / xpat2-1.04 / src / X-gfx1.c < prev    next >
C/C++ Source or Header  |  1994-09-28  |  35KB  |  1,180 lines

  1. /*****************************************************************************/
  2. /*                                         */
  3. /*                                         */
  4. /*    X patience version 2 -- module X-gfx1.c                     */
  5. /*                                         */
  6. /*    card graphics for the X interface                     */
  7. /*    written by Heiko Eissfeldt and Michael Bischoff                 */
  8. /*    based on the gfx.c module from Spider by Dave Lemke             */
  9. /*    see COPYRIGHT.xpat2 for Copyright details                 */
  10. /*                                         */
  11. /*                                         */
  12. /*****************************************************************************/
  13. #include "X-pat.h"
  14.  
  15. #ifndef NO_XPM
  16. #include <xpm.h>
  17. #endif
  18. #ifndef NO_ROUND_CARDS
  19. #include <X11/Xmu/Drawing.h>
  20. #endif
  21.  
  22. #ifdef SAVE_IMAGES
  23. #ifdef NO_XPM
  24. #error "Cannot define SAVE_IMAGES with NO_XPM"
  25. #endif
  26. static void write_pixmap(const char *filename, Pixmap pict, Pixmap clip) {
  27.     if (XpmWriteFileFromPixmap(dpy, filename, pict, clip, NULL) != XpmSuccess)
  28.         fprintf(stderr, "error writing xpm file %s\n", filename);
  29. }
  30. #endif
  31.  
  32. static int read_pixmap(const char *filename, Pixmap *pict) {
  33. #ifndef NO_XPM
  34.     if (XpmReadFileToPixmap(dpy, table, filename, pict, NULL, NULL) == XpmSuccess) {
  35.     /* add nice outline which may vary (-cround option) */
  36. #ifndef NO_ROUND_CARDS
  37.     if (ROUND_W)
  38.         XmuDrawRoundedRectangle(dpy, *pict,
  39.             blackgc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  40.     else
  41. #endif
  42.         XDrawRectangle(dpy, *pict, blackgc,
  43.                0, 0, CARD_WIDTH-1, CARD_HEIGHT-1);
  44.     return 1;
  45.     }
  46. #endif
  47.     *pict = 0;
  48.     return 0;
  49. }
  50.  
  51.  
  52.  
  53. /* card INFO: taken from spider */
  54. /* these are for the large cards */
  55. /* all small card info is variable */
  56.  
  57. #define FCARD_WIDTH    79
  58. #define FCARD_HEIGHT    123
  59.  
  60. /* this is the size of the bounding rectangle of the pictures for internal cards */
  61. #define    FACECARD_WIDTH    48
  62. #define    FACECARD_HEIGHT    92
  63.  
  64. #define    RANK_WIDTH    9
  65. #define    RANK_HEIGHT    14
  66.  
  67. #define    RANK_LOC_X    4
  68. #define    RANK_LOC_Y    7
  69.  
  70. #define    SMALL_LOC_X    4
  71. #define    SMALL_LOC_Y    (RANK_HEIGHT + RANK_LOC_Y + 3)
  72.  
  73. #define    MID_CARD_X    (CARD_WIDTH/2)
  74. #define    MID_CARD_Y    (CARD_HEIGHT/2)
  75.  
  76. #define    CARD_COL1_X    (3 * CARD_WIDTH/10)
  77. #define    CARD_COL2_X    (CARD_WIDTH/2)
  78. #define    CARD_COL3_X    (7 * CARD_WIDTH/10)
  79.  
  80. /* 5 diff rows for the two main columns */
  81. /* 1 and 5 are top and bottom, 3 is the middle */
  82. /* 2 & 4 are for the 10 & 9 */
  83. #define    CARD_ROW1_Y    (CARD_HEIGHT/5)
  84. #define    CARD_ROW2_Y    (2 * CARD_HEIGHT/5)
  85. #define    CARD_ROW3_Y    (CARD_HEIGHT/2)
  86. #define    CARD_ROW4_Y    (CARD_HEIGHT - 2 * CARD_HEIGHT/5)
  87. #define    CARD_ROW5_Y    (CARD_HEIGHT - CARD_HEIGHT/5)
  88.  
  89. /* between 1 & 3, 3 & 5 */
  90. #define    CARD_SEVEN_Y    (7 * CARD_HEIGHT/20)
  91. #define    CARD_EIGHT_Y    (CARD_HEIGHT - 7 * CARD_HEIGHT/20)
  92.  
  93. /* between rows 1 & 2, 4 & 5 */
  94. #define    CARD_TEN_Y1    (3 * CARD_HEIGHT/10)
  95. #define    CARD_TEN_Y2    (CARD_HEIGHT - 3 * CARD_HEIGHT/10)
  96.  
  97. /* pip info */
  98. #define    PIP_WIDTH    10
  99. #define    PIP_HEIGHT    10
  100.  
  101.  
  102.  
  103. #define    NUM_RANKS    13
  104. #define    NUM_SUITS    4
  105. #define    CARDS_PER_DECK    (NUM_RANKS * NUM_SUITS)
  106.  
  107.  
  108. static GC cardgc;        /* gc in use when drawing cards */
  109. static GC backgc;        /* gc in use when drawing cardbacks */
  110. static GC redgc;        /* gc for red parts of the cards */
  111.  
  112. /* default cards: */
  113. #include "rank.bm"    /* rank symbol bitmaps             */
  114. #include "face.bm"    /* bitmaps for jack, queen and king     */
  115. #include "suit.bm"    /* suit bitmaps             */
  116. #include "logo.bm"    /* bitmap used for cardbacks         */
  117.  
  118. static struct suit_tab {
  119.     char *bits;
  120.     int w;
  121.     int h;
  122. } suit_tab[] = {
  123.     { club_bits, club_width, club_height },
  124.     { spade_bits, spade_width, spade_height },
  125.     { heart_bits, heart_width, heart_height },
  126.     { diamond_bits, diamond_width, diamond_height }
  127. }, suit_sm_tab[] = {
  128.     { club_sm_bits, club_sm_width, club_sm_height },
  129.     { spade_sm_bits, spade_sm_width, spade_sm_height },
  130.     { heart_sm_bits, heart_sm_width, heart_sm_height },
  131.     { diamond_sm_bits, diamond_sm_width, diamond_sm_height }
  132. }, suit_lg_tab[] = {
  133.     { NULL, club_width, club_height },
  134.     { spade_lg_bits, spade_lg_width, spade_lg_height },
  135.     { NULL, heart_width, heart_height },
  136.     { NULL, diamond_width, diamond_height }
  137. };
  138.  
  139. static Pixmap rank_map[NUM_RANKS],     rank_r_map[NUM_RANKS];
  140. static Pixmap rank_map_red[NUM_RANKS], rank_r_map_red[NUM_RANKS];
  141. static Pixmap suit_map[NUM_SUITS],     suit_r_map[NUM_SUITS];
  142. static Pixmap suit_sm_map[NUM_SUITS],  suit_sm_r_map[NUM_SUITS];
  143. static Pixmap suit_lg_map[NUM_SUITS];
  144. static Pixmap jack_map[NUM_SUITS], queen_map[NUM_SUITS], king_map[NUM_SUITS];
  145. static Pixmap joker_map;
  146.  
  147. #include "Joker.bm"
  148.  
  149. #ifdef STATIC_CLIPMAPS
  150. #include "clip7.bm"
  151. #include "clip4.bm"
  152. #endif
  153.  
  154. static GC cardbackgc;
  155. #ifndef NO_ROUND_CARDS
  156. static Pixmap cardclipmap;
  157. #endif
  158.  
  159. static int mem_option;
  160. static const char *xpmdir;
  161. static Pixmap cardpicts[58];
  162.  
  163. /* clipping rectangles */
  164. static XRectangle cliprects[1] = {{ 0, 0, 0, 0 }};
  165. static int card_is_clipped;    /* optimizer for card drawing */
  166.  
  167. #include "gray1.bm"
  168.  
  169. static void make_GCs(unsigned long red, unsigned long cbcolor) {
  170.     XGCValues gcv;
  171.     long gcflags;
  172.     Pixmap tmpmap;
  173.     GC logogc;
  174.     Pixmap logomap;
  175.  
  176.     gcv.graphics_exposures = False;
  177.     /* make GC for RED */
  178.     if (graphic.is_color)    {
  179.     gcv.foreground = red;
  180.     gcv.background = WhitePixel(dpy, screen);
  181.     gcflags = GCForeground | GCBackground | GCGraphicsExposures;
  182.     redgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  183.     } else    {
  184.     gcv.tile = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  185.          gray1_bits, gray1_width, gray1_height);
  186.     gcv.fill_style = FillTiled;
  187.     gcv.foreground = BlackPixel(dpy, screen);
  188.     gcv.background = WhitePixel(dpy, screen);
  189.     
  190.     gcflags = GCTile | GCForeground | GCBackground |
  191.         GCFillStyle | GCGraphicsExposures;
  192.     redgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  193.     }
  194.  
  195.     /* make GC for cardbacks */
  196.     tmpmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  197.     logo_bits, logo_width, logo_height);
  198.     logomap = XCreatePixmap(dpy, RootWindow(dpy, screen),
  199.     logo_width, logo_height, DefaultDepth(dpy, screen));
  200.     
  201.     gcv.foreground = BlackPixel(dpy, screen);
  202.     gcv.background = WhitePixel(dpy, screen);
  203.     gcv.graphics_exposures = True;
  204.     gcflags = GCForeground | GCBackground | GCGraphicsExposures;
  205.     
  206.     cardbackgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  207.     
  208.     if (graphic.is_color)    {
  209.     gcv.foreground = cbcolor;
  210.     gcv.background = WhitePixel(dpy, screen);
  211.     gcflags = GCForeground | GCBackground;
  212.     logogc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  213.     XCopyPlane(dpy, tmpmap, logomap, logogc, 0, 0, 
  214.            logo_width, logo_height, 0, 0, 1);
  215.     XFreeGC(dpy, logogc);
  216.     } else    {
  217.     XCopyPlane(dpy, tmpmap, logomap, whitegc, 0, 0, 
  218.            logo_width, logo_height, 0, 0, 1);
  219.     }
  220.     XFreePixmap(dpy, tmpmap);
  221.     
  222.     gcv.tile = logomap;
  223.     gcv.fill_style = FillTiled;
  224.     gcflags |= GCTile | GCFillStyle | GCGraphicsExposures;
  225.     
  226.     backgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  227. }
  228.  
  229. #define S(x,y) src[(H-1-(y))*W+(x)]
  230. #define D(x,y) dst[(H-1-(y))*W+(x)]
  231.  
  232. /* table for left-right mirroring of bitmaps */
  233. static char _reverse_byte[0x100] = {
  234.     0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
  235.     0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
  236.     0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
  237.     0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
  238.     0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
  239.     0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
  240.     0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
  241.     0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
  242.     0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
  243.     0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
  244.     0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
  245.     0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
  246.     0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
  247.     0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
  248.     0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
  249.     0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
  250.     0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
  251.     0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
  252.     0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
  253.     0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
  254.     0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
  255.     0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
  256.     0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
  257.     0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
  258.     0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
  259.     0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
  260.     0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
  261.     0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
  262.     0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
  263.     0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
  264.     0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
  265.     0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
  266. };
  267.  
  268.  
  269.  
  270. static void copy_upside_down(char *src, char *dst, int W, int H)
  271. {   int x, y;
  272.     
  273.     W = (W + 7)/8;              /* round up to bytes */
  274.     for (y = 0; y < H; y++)    {
  275.     for (x = 0; x < W; x++)    {
  276.         D (x, y) = S (x, H - 1 - y);
  277.     }
  278.     }
  279. }
  280.  
  281. /* copy a bitmap rotated from source to dest */
  282. static void rot_180(char *src, char *dst, int W, int H)
  283. {   int x, y;
  284.     int width = W;
  285.     char *new;
  286.     int bit;
  287.     
  288.     W = (W + 7)/8;              /* round up to bytes */
  289.     for (y = 0; y < H; y++) {
  290.     for (x = 0; x < W; x++) {
  291.         D (x, y) = _reverse_byte[(unsigned char)(S (W - 1 - x, H - 1 - y))];
  292.     }
  293.     }
  294.     
  295.     /* shift it over (bit correction) */
  296.     new = calloc((size_t)W*H, 1);
  297.     for (y = 0; y < H; y++)    {
  298.     for (x = 0; x < W*8; x++)    {
  299.         bit = (*(dst + (x + (W*8 - width))/8 + y * W)
  300.            & (1 << ((x + (W*8 - width)) % 8))) ? 1 : 0;
  301.         *(new + x/8 + y*W) = (bit << (x%8)) | 
  302.         (*(new + x/8 + y*W) & ~(1 << (x%8)));
  303.     }
  304.     }
  305.     memcpy(dst, new, W*H);
  306.     free(new);
  307. }
  308.  
  309.  
  310.  
  311.  
  312. /* large cards: */
  313. /*
  314.  * make a 'red' pixmap by setting the clipmask to the desired shape and 
  315.  * pushing 'red' through it
  316.  */
  317.  
  318. static Pixmap make_color_map(char *bits, int width, int height, Suit suit)
  319. {   Pixmap    tmpmap, newmap;
  320.     static GC    cleargc = (GC) 0;
  321.     XGCValues    xgcv;
  322.     
  323.     if (suit == Spade || suit == Club || graphic.is_color)
  324.     return XCreateBitmapFromData(dpy, RootWindow(dpy, screen), bits, width, height);
  325.  
  326.     /* get a graphic context, if not yet gotten */
  327.     if (cleargc == (GC) 0) {
  328.     xgcv.function = GXclear;
  329.     cleargc = XCreateGC(dpy, RootWindow(dpy, screen), GCFunction, &xgcv);
  330.     }
  331.     tmpmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  332.         bits, width, height);        /* turn data into bitmap */
  333.     
  334.     /* allocate a pixmap */
  335.     newmap = XCreatePixmap(dpy, RootWindow(dpy, screen), width, height, 1);
  336.     
  337.     /* clear red_map to white */
  338.     XFillRectangle(dpy, newmap, cleargc, 0, 0, width, height);
  339.     
  340.     /* use bitmap tmpmap as clipmap for red GC */
  341.     XSetClipMask(dpy, redgc, tmpmap);
  342.     /* color red_map to red using the mask */
  343.     XFillRectangle(dpy, newmap, redgc, 0, 0, width, height);
  344.     XSetClipMask(dpy, redgc, None);        /* clear clipping mask in the red GC */
  345.     XFreePixmap(dpy, tmpmap);            /* release bitmap */
  346.   
  347.     return (newmap);
  348. }
  349.  
  350.  
  351. #ifdef LOADCARDS
  352. static Pixmap card_bitmaps[68];    /* these hold pixmaps of full depth */
  353.                                 /* we have room for 8 jokers */
  354. static int numcards;        /* when reading external cardsets */
  355. static int inset;
  356.  
  357. /* read a complete set of card bitmaps from a file */
  358. static void read_bitmap(const char *file)
  359. {   FILE *fp;
  360.     int i, w, h, bpl, cardsize;
  361.     char *card_bits;
  362.     char fullname[200];
  363.     struct {             /* Note: all hi...-fields are currently 0 */
  364.     char type;               /* 0 for cards without and 1 for cards with an frame     */
  365.     char hitype;
  366.     char num;                /* # of cards (without jokers) in file         */
  367.     char hinum;
  368.     char x;                  /* width of one card                     */
  369.     char hix;
  370.     char y;                  /* height of one card on screen (size in file can differ) */
  371.     char hiy;
  372.     char rx;                 /* horizontal half axe of rounded corner         */
  373.     char hirx;
  374.     char ry;                 /* vertical half axe of rounded corner         */
  375.     char hiry;
  376.     char stddelta;           /* fraction of height for displaying             */
  377.     char histddelta;
  378.     char numjokers;          /* # of different joker cards             */
  379.     char hinumjokers;
  380.     char numcardbacks;       /* # of different cardbacks                 */
  381.     char hinumcardbacks;
  382.     char fill[14];           /* reserved for future requirements             */
  383.     } hdr;
  384.  
  385.     if (!strchr(file, '/') &&
  386.     strlen(file) + strlen(LIBDIR) + 8 <= sizeof(fullname)) {
  387.     sprintf(fullname, "%s/%s.cards", LIBDIR, file);
  388.     file = fullname;
  389.     }
  390.     fp = fopen(file, "r");
  391.     if (!fp || fread(&hdr, sizeof(hdr), 1, fp) != 1) {
  392.     fprintf(stderr, "cannot read file %s\n", file);
  393.     exit(EXIT_FAILURE);
  394.     }
  395.     /* check the number of cards in the header */
  396.     if (hdr.num < 52 || hdr.num > 57) {
  397.     fprintf(stderr, "Bad value of numcards in file %s\n", file);
  398.     exit(EXIT_FAILURE);
  399.     }
  400.     w = hdr.x; h = hdr.y; numcards = hdr.num;
  401.     CARD_WIDTH = w;
  402.     CARD_HEIGHT = h;
  403.     ROUND_W = hdr.rx;           /* default radii of rounded corners */
  404.     ROUND_H = hdr.ry;
  405.     STD_DELTA = hdr.stddelta;
  406.     bpl = (w + 7) >> 3;         /* bytes per line */
  407.     if (!(card_bits = malloc(bpl * h * numcards))) {
  408.     fprintf(stderr, "Not enough memory for external cardset (file %s)\n",
  409.         file);
  410.     exit(EXIT_FAILURE);
  411.     }
  412.  
  413.     /* read the card bitmaps */
  414.     fread(card_bits, bpl * h * numcards, 1, fp);
  415.     fclose(fp);
  416.  
  417.     /* hdr.type & 1 is the number of pixels omitted in the bitmap */
  418.     cardsize = (h - 2 * (inset = (hdr.type & 1))) * bpl;
  419.  
  420.     /* turn data into bitmaps */
  421.     for (i = 0; i < numcards; i++)    {
  422.     card_bitmaps[i] = XCreateBitmapFromData(dpy, 
  423.         RootWindow(dpy, screen), card_bits+i*cardsize, w-2*inset, h-2*inset);
  424.     }
  425. }
  426. #endif
  427.  
  428. /* build jack to king bitmaps of the internal cardset by mirroring the first half */
  429. static char *compose_picture(char *tmp, const char *orgbits)
  430. {   int cardsize = 6 * 45; /* omit one scanline */
  431.     memcpy(tmp, orgbits, cardsize);
  432.     rot_180(tmp, tmp+cardsize+6, 47, 45);
  433.     memset(tmp + cardsize, 0xff, 6);            /* add a horizontal line in the middle */
  434.     return tmp;
  435. }
  436.  
  437. static void build_internal_cardset(void)
  438. {   char new_bits[120/8 * 200];    /* sufficient for the largest bitmap here */
  439.     Rank r;
  440.     int i;
  441.  
  442.     ROUND_W = ROUND_H = 9;
  443.     STD_DELTA = 25;
  444.     
  445.     /* create bitmaps for rank symbols normal and rotated */
  446.     for (r = Ace; r <= King; r++)    {
  447.     rank_map[(int)r] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  448.          rank_bits[(int)r], rank_width, rank_height);
  449.     rot_180(rank_bits[(int)r], new_bits, rank_width, rank_height);
  450.     rank_r_map[(int)r] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  451.            new_bits, rank_width, rank_height);
  452.     if (graphic.is_color)    {
  453.         rank_map_red[(int)r] = rank_map[(int)r];
  454.         rank_r_map_red[(int)r] = rank_r_map[(int)r];
  455.     } else {
  456.         rank_map_red[(int)r] = make_color_map(
  457.             rank_bits[(int)r], rank_width, rank_height, Heart);
  458.         rank_r_map_red[(int)r] = make_color_map(
  459.               new_bits, rank_width, rank_height, Heart);
  460.     }
  461.     }
  462.  
  463.     for (i = 0; i < 4; ++i) {
  464.     struct suit_tab *bp;
  465.     char *king_bits[] = { king_c_bits, king_s_bits, king_h_bits, king_d_bits };
  466.     char *queen_bits[] = { queen_c_bits, queen_s_bits, queen_h_bits, queen_d_bits };
  467.     char *jack_bits[] = { jack_c_bits, jack_s_bits, jack_h_bits, jack_d_bits };
  468.  
  469.     bp = suit_tab + i;
  470.     copy_upside_down(bp->bits, new_bits, bp->w, bp->h);
  471.     suit_map[i] = make_color_map(bp->bits, bp->w, bp->h, (Suit)i);
  472.     suit_r_map[i] = make_color_map(new_bits, bp->w, bp->h, (Suit)i);
  473.  
  474.     bp = suit_sm_tab + i;
  475.     copy_upside_down(bp->bits, new_bits, bp->w, bp->h);
  476.     suit_sm_map[i] = make_color_map(bp->bits, bp->w, bp->h, (Suit)i);
  477.     suit_sm_r_map[i] = make_color_map(new_bits, bp->w, bp->h, (Suit)i);
  478.     bp = suit_lg_tab + i;
  479.     suit_lg_map[i] = bp->bits ? make_color_map(bp->bits, bp->w, bp->h, (Suit)i) :
  480.         suit_map[i];
  481.  
  482.     jack_map[i] = make_color_map(compose_picture(new_bits, jack_bits[i]),
  483.                      47, 91, (Suit)i);
  484.     queen_map[i] = make_color_map(compose_picture(new_bits, queen_bits[i]),
  485.                      47, 91, (Suit)i);
  486.     king_map[i] = make_color_map(compose_picture(new_bits, king_bits[i]),
  487.                      47, 91, (Suit)i);
  488.     }
  489.     joker_map = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  490.         Joker_bits, Joker_width, Joker_height);     /* turn data into bitmap */
  491. }
  492.  
  493. void init_cards(const char *cardset, int rx, int ry,
  494.     unsigned long red, unsigned long cbcolor, int mem, const char *xpm) {
  495. #ifdef NO_ROUND_CARDS
  496.     rx = ry = 0;
  497. #endif
  498.     mem_option = mem;
  499.     if (xpm && *xpm != '.' && *xpm != '/') {
  500.     char *s;
  501.     s = malloc(strlen(LIBDIR) + strlen(xpm) + 2);
  502.     sprintf(s, "%s/%s", LIBDIR, xpm);
  503.     xpmdir = s;
  504.     } else
  505.     xpmdir = xpm;    /* directory where to load from the Xpm-files */
  506.  
  507.     card.cardset = cardset;
  508.     make_GCs(red, cbcolor);
  509.     if (cardset) {    /* read external cardset */
  510. #ifdef LOADCARDS
  511.     read_bitmap(cardset)
  512. #endif
  513.         ;
  514.     } else {
  515.         /* build internal cardset */
  516.     CARD_WIDTH = -1;
  517.     if (xpm) {
  518.         char s[200];
  519.         FILE *fp;
  520.         sprintf(s, "%s/Cards.conf", xpmdir);
  521.         if ((fp = fopen(s, "r"))) {
  522.         if (fscanf(fp, "%d %d", &CARD_WIDTH, &CARD_HEIGHT) != 2)
  523.             CARD_WIDTH = -1;
  524.         fclose(fp);
  525.         }
  526.     }    
  527.     if (CARD_WIDTH < 49 || CARD_WIDTH > 120
  528.            || CARD_HEIGHT < 95 || CARD_HEIGHT > 200) {
  529.         CARD_WIDTH = FCARD_WIDTH;
  530.         CARD_HEIGHT = FCARD_HEIGHT;
  531.     }
  532.     build_internal_cardset();
  533.     }
  534.     
  535.     cliprects[0].width = CARD_WIDTH + 1;
  536.     /* sanity checks: */
  537.     if (2 * rx >= (int)CARD_WIDTH)
  538.     rx = CARD_WIDTH / 2;
  539.     if (2 * ry >= (int)CARD_HEIGHT)
  540.     ry = CARD_HEIGHT / 2;
  541.     /* assign values */
  542.     if (rx >= 0)
  543.     card.rx = rx;
  544.     if (ry >= 0)
  545.     card.ry = ry;
  546.     
  547.     /* adapt arrows to match cardset sizes */
  548.     graphic.aw = graphic.ah = STD_DELTA / 6;
  549.     graphic.ya_h = graphic.xa_w = graphic.aw * 2;
  550.     graphic.xa_h = graphic.ya_w = graphic.aw * 4;
  551.  
  552.     card.back_delta_x = (CARD_WIDTH - logo_width)/2;
  553.     card.back_delta_y = (CARD_HEIGHT - logo_height)/2;
  554.  
  555.     /* finally, compute a clipping mask for the cards */
  556.     /* apply this clip mask to cardbackgc */
  557. #ifndef NO_ROUND_CARDS
  558. #ifndef STATIC_CLIPMAPS
  559.     if (ROUND_W) {
  560.     cardclipmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
  561.                     CARD_WIDTH+1, CARD_HEIGHT+1, 1);
  562.     {    XGCValues    gcv;
  563.          long gcflags, f, b;
  564.          GC clipgc;
  565.          
  566.          b = 0;
  567.          f = 1;
  568.          /* first, clear the clipmap */
  569.          /* (is it possible to do it easier?) */
  570.          gcv.foreground = b;
  571.          gcv.background = f;
  572.          gcv.graphics_exposures = False;
  573.          gcflags = GCForeground | GCBackground | GCGraphicsExposures;
  574.          clipgc = XCreateGC(dpy, cardclipmap, gcflags, &gcv);
  575.          XFillRectangle(dpy, cardclipmap, clipgc, 0, 0, 
  576.                 CARD_WIDTH, CARD_HEIGHT);
  577.          XFreeGC(dpy, clipgc);
  578.          
  579.          /* make gc for clipgc */
  580.          gcv.foreground = f;
  581.          gcv.background = b;
  582.          gcv.graphics_exposures = False;
  583.          gcflags = GCForeground | GCBackground | GCGraphicsExposures;
  584.          clipgc = XCreateGC(dpy, cardclipmap, gcflags, &gcv);
  585.          XmuFillRoundedRectangle(dpy, cardclipmap, clipgc, 0, 0, 
  586.              CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  587.          XmuDrawRoundedRectangle(dpy, cardclipmap, clipgc, 0, 0, 
  588.              CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  589.          XFreeGC(dpy, clipgc);
  590.      }
  591. #ifdef DEBUG
  592.     XWriteBitmapFile(dpy, "clip.mask.bm", cardclipmap, CARD_WIDTH, CARD_HEIGHT, -1, -1);
  593. #endif
  594.     /* fill the background */
  595.     XSetClipMask(dpy, cardbackgc, cardclipmap);
  596.     }
  597. #else
  598.     switch (ROUND_H) {
  599.     case 3:
  600.     case 4:
  601.     case 5:
  602.     cardclipmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  603.         clip4_bits, clip4_width, clip4_height);
  604.     XSetClipMask(dpy, cardbackgc, cardclipmap);
  605.     break;
  606.     case 6:
  607.     case 7:
  608.     case 8:
  609.     case 9:
  610.     cardclipmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  611.             clip7_bits, clip7_width, clip7_height);
  612.     XSetClipMask(dpy, cardbackgc, cardclipmap);
  613.     break;
  614.     }
  615. #endif
  616. #endif
  617. }
  618.  
  619.  
  620.  
  621. static void paint_cardback(int x, int y, int delta, Drawable d)
  622. {
  623.         if (!delta)
  624.             delta = CARD_HEIGHT;
  625.  
  626. #define    INSETa    1
  627. #define INSETb  1
  628.     /* change the origin so cards will have the same back anywhere
  629.      * on the table
  630.      */
  631.     /*
  632.      * there should be a tile centered in the card, with the
  633.      * surrounding tiles being partial
  634.      */
  635.     XSetClipMask(dpy, backgc, None);
  636.     XSetClipMask(dpy, blackgc, None);
  637.  
  638. #ifndef NO_ROUND_CARDS
  639.     if (ROUND_W) {
  640.  
  641.         XmuFillRoundedRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, 
  642.         (delta == CARD_HEIGHT) ? delta-1 : delta + ROUND_H * 2,
  643.         ROUND_W, ROUND_H);
  644.     } else
  645. #endif
  646.         XFillRectangle(dpy, d, blackgc, x, y, CARD_WIDTH,
  647.         (delta == CARD_HEIGHT) ? delta : delta);
  648.  
  649.     XSetTSOrigin(dpy, backgc, x + card.back_delta_x, y + card.back_delta_y);
  650.  
  651. #ifndef NO_ROUND_CARDS
  652.     if (ROUND_W)
  653.         XmuFillRoundedRectangle(dpy, d, backgc, x + INSETa, y + INSETa, 
  654.         CARD_WIDTH - INSETa - INSETb - 1,
  655.         (delta == CARD_HEIGHT) ? 
  656.             (CARD_HEIGHT - INSETa - INSETb - 1) : delta + ROUND_H * 2,
  657.         ROUND_W, ROUND_H);
  658.     else
  659. #endif
  660.         XFillRectangle(dpy, d, backgc, x + INSETa, y + INSETa, 
  661.         CARD_WIDTH - INSETa - INSETb - 1,
  662.         (delta == CARD_HEIGHT) ? 
  663.             (CARD_HEIGHT - INSETa - INSETb - 1) : delta-1);
  664.     /* correction */
  665. #ifndef NO_ROUND_CARDS
  666.     if (ROUND_W) {
  667.         XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, 
  668.         (delta == CARD_HEIGHT) ? delta-1 : delta + ROUND_H * 2,
  669.         ROUND_W, ROUND_H);
  670.         XmuDrawRoundedRectangle(dpy, d, blackgc, x+1, y+1, CARD_WIDTH-3, 
  671.         (delta == CARD_HEIGHT) ? delta-3 : delta + ROUND_H * 2,
  672.         ROUND_W-1, ROUND_H-1);
  673.     } else
  674. #endif
  675.         XDrawRectangle(dpy, d, blackgc, x+1, y+1, CARD_WIDTH-2,
  676.         (delta == CARD_HEIGHT) ? delta-2 : delta);
  677.  
  678. }
  679.  
  680.  
  681. /*
  682.  * NOTE -- for all the pip drawers except the one that actually plots the
  683.  * bits, the location is the card's location.  the drawer's take the
  684.  * pip's center as location.
  685.  */
  686.  
  687. /*
  688.  * draws right-side-up pip
  689.  *
  690.  * location is for center of pip
  691.  */
  692.  
  693. static void draw_pip(Suit suit, int x, int y, Drawable d)
  694. {
  695.     XCopyPlane(dpy, suit_map[suit], d, cardgc, 0, 0, 
  696.         suit_tab[suit].w, suit_tab[suit].h, x - 15/2, y - 19/2, 1);
  697. }
  698.  
  699. /*
  700.  * draws upside-down pip
  701.  *
  702.  * location is for center of pip
  703.  */
  704. static void draw_did(Suit suit, int x, int y, Drawable d)
  705. {
  706.     if (card_is_clipped)    /* a clipped card never shows any did's */
  707.     return;
  708.     XCopyPlane(dpy, suit_map[suit], d, cardgc, 0, 0, 
  709.         suit_tab[suit].w, suit_tab[suit].h, x - 15/2, y - 19/2, 1);
  710. }
  711.  
  712. /*
  713.  * draws big center pip
  714.  */
  715. static void draw_center_pip(Suit suit, int x, int y, Drawable d)
  716. {   int w, h;
  717.     if (card_is_clipped)    /* a clipped card never shows any big's */
  718.     return;
  719.     w = suit_lg_tab[suit].w;
  720.     h = suit_lg_tab[suit].h;
  721.     XCopyPlane(dpy, suit_lg_map[suit], d, cardgc, 0, 0, w, h,
  722.     x - w/2, y - h/2, 1);
  723. }
  724.  
  725. /* 
  726.  * draw_two_pips
  727.  */
  728. static void draw_two_pips(Suit suit, int x, int y, Drawable d)
  729. {
  730.     draw_pip(suit, x + MID_CARD_X, y + CARD_ROW1_Y, d);
  731.     draw_did(suit, x + MID_CARD_X, y + CARD_ROW5_Y, d);
  732. }
  733.  
  734. /*
  735.  * draw_four_pips
  736.  */
  737. static void draw_four_pips(Suit suit, int x, int y, Drawable d)
  738. {
  739.     draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y, d);
  740.     draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y, d);
  741.  
  742.     draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y, d);
  743.     draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y, d);
  744. }
  745.  
  746. static void draw_six_pips(Suit suit, int x, int y, Drawable d)
  747. {
  748.     draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y, d);
  749.     draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y, d);
  750.  
  751.     if (card_is_clipped)
  752.         return;
  753.  
  754.     /* these are only visible when its not clipped */
  755.     draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW3_Y, d);
  756.     draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y, d);
  757.  
  758.     draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW3_Y, d);
  759.     draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y, d);
  760. }
  761.  
  762. static void draw_eight_pips(Suit suit, int x, int y, Drawable d)
  763. {
  764.     draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y, d);
  765.     draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y, d);
  766.  
  767.     if (card_is_clipped)
  768.         return;
  769.  
  770.     /* these are only visible when its not clipped */
  771.     draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW2_Y, d);
  772.     draw_did(suit, x + CARD_COL1_X, y + CARD_ROW4_Y, d);
  773.     draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y, d);
  774.  
  775.     draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW2_Y, d);
  776.     draw_did(suit, x + CARD_COL3_X, y + CARD_ROW4_Y, d);
  777.     draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y, d);
  778. }
  779.  
  780. static void draw_jack(Suit suit, int x, int y, Drawable d)
  781. {
  782.     XCopyPlane(dpy, jack_map[suit], d, cardgc, 
  783.         0, 0, FACECARD_WIDTH-1, FACECARD_HEIGHT-1,
  784.         x + 1 + (CARD_WIDTH - FACECARD_WIDTH)/2, 
  785.         y + 1 + (CARD_HEIGHT - FACECARD_HEIGHT)/2, 1);
  786.  
  787.     XDrawRectangle(dpy, d, cardgc,
  788.         x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
  789.         y + (CARD_HEIGHT - FACECARD_HEIGHT)/2,
  790.         FACECARD_WIDTH, FACECARD_HEIGHT);
  791. }
  792.  
  793. static void draw_queen(Suit suit, int x, int y, Drawable d)
  794. {
  795.     XCopyPlane(dpy, queen_map[suit], d, cardgc,
  796.         0, 0, FACECARD_WIDTH-1, FACECARD_HEIGHT-1,
  797.         x + 1+(CARD_WIDTH - FACECARD_WIDTH)/2, 
  798.         y + 1+(CARD_HEIGHT - FACECARD_HEIGHT)/2, 1);
  799.  
  800.     XDrawRectangle(dpy, d, cardgc,
  801.         x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
  802.         y + (CARD_HEIGHT - FACECARD_HEIGHT)/2,
  803.         FACECARD_WIDTH, FACECARD_HEIGHT);
  804. }
  805.  
  806. static void draw_king(Suit suit, int x, int y, Drawable d)
  807. {
  808.     XCopyPlane(dpy, king_map[suit], d, cardgc,
  809.         0, 0, FACECARD_WIDTH-1, FACECARD_HEIGHT-1,
  810.         x + 1+(CARD_WIDTH - FACECARD_WIDTH)/2, 
  811.         y + 1+(CARD_HEIGHT - FACECARD_HEIGHT)/2, 1);
  812.  
  813.     XDrawRectangle(dpy, d, cardgc,
  814.         x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
  815.         y + (CARD_HEIGHT - FACECARD_HEIGHT)/2,
  816.         FACECARD_WIDTH, FACECARD_HEIGHT);
  817. }
  818.  
  819. static void draw_rank(int x, int y, Rank rank, Suit suit, Drawable d)
  820. {
  821.  
  822.     if (suit == Heart || suit == Diamond)    {
  823.         XCopyPlane(dpy, rank_map_red[rank], d, cardgc,
  824.             0, 0, RANK_WIDTH, RANK_HEIGHT,
  825.             x + RANK_LOC_X, y + RANK_LOC_Y, 1);
  826.  
  827.         if (!card_is_clipped)
  828.             XCopyPlane(dpy, rank_r_map_red[rank], d, cardgc,
  829.             0, 0, RANK_WIDTH, RANK_HEIGHT,
  830.             x + (CARD_WIDTH - RANK_WIDTH - RANK_LOC_X), 
  831.             y + (CARD_HEIGHT - RANK_HEIGHT - RANK_LOC_Y), 1);
  832.     } else    {
  833.         XCopyPlane(dpy, rank_map[rank], d, cardgc,
  834.             0, 0, RANK_WIDTH, RANK_HEIGHT,
  835.             x + RANK_LOC_X, y + RANK_LOC_Y, 1);
  836.  
  837.         if (!card_is_clipped)
  838.             XCopyPlane(dpy, rank_r_map[rank], d, cardgc,
  839.             0, 0, RANK_WIDTH, RANK_HEIGHT,
  840.             x + (CARD_WIDTH - RANK_WIDTH - RANK_LOC_X), 
  841.             y + (CARD_HEIGHT - RANK_HEIGHT - RANK_LOC_Y), 1);
  842.     }
  843.  
  844.     {    int w, h, o;
  845.     w = suit_sm_tab[suit].w;
  846.     h = suit_sm_tab[suit].h;
  847.     o = (suit == Diamond);
  848.     XCopyPlane(dpy, suit_sm_map[suit], d, cardgc, 0, 0, w, h,
  849.         x + o + SMALL_LOC_X, y + SMALL_LOC_Y, 1);
  850.  
  851.     if (!card_is_clipped)
  852.         XCopyPlane(dpy, suit_sm_r_map[suit], d, cardgc, 0, 0, w, h,
  853.         x - o + (CARD_WIDTH - w - SMALL_LOC_X),
  854.         y + (CARD_HEIGHT - h - SMALL_LOC_Y), 1);
  855.     }
  856. }
  857.  
  858.  
  859.  
  860. static void paint_joker(int x, int y, Drawable d)
  861. {
  862. #ifndef NO_ROUND_CARDS
  863.     if (ROUND_W) {
  864.     XSetClipMask(dpy, blackgc, cardclipmap);
  865.     XSetClipOrigin(dpy, blackgc, x, y);
  866.     }
  867. #endif
  868.  
  869.     XCopyPlane(dpy, joker_map, d, blackgc, 0, 0, CARD_WIDTH, CARD_HEIGHT,
  870.            x, y, 1);
  871.  
  872. #ifndef NO_ROUND_CARDS
  873.     if (ROUND_W)
  874.     XSetClipMask(dpy, blackgc, None);
  875.  
  876.     if (ROUND_W)
  877.     XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, 
  878.             CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  879.     else
  880. #endif
  881.     /* draw border on card */
  882.     XDrawRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1);
  883. }
  884. /*
  885.  * delta is 0 if the card is fully showing
  886.  */
  887. static void paint_large_card(int x, int y, int rank, Suit suit, int delta, Drawable d)
  888. {
  889.     if (suit == Spade || suit == Club)    {
  890.         cardgc = blackgc;
  891.     } else    {
  892.         cardgc = redgc;
  893.     }
  894.  
  895.     if (delta) {
  896.         cliprects[0].height = delta + ROUND_H;
  897.         XSetClipRectangles(dpy, cardgc, x, y, cliprects, 1, Unsorted);
  898. #ifndef NO_ROUND_CARDS
  899.         if (ROUND_W)    {
  900.             XSetClipRectangles(dpy, whitegc, x, y, cliprects, 1, 
  901.                         Unsorted);
  902.             if (cardgc != blackgc)
  903.             XSetClipRectangles(dpy, blackgc, x, y, cliprects, 1,
  904.                         Unsorted);
  905.  
  906.             /* add in ROUND_H to height so only the top is rounded */
  907.             /* fill the background */
  908.             XmuFillRoundedRectangle(dpy, d, whitegc, x, y, 
  909.             CARD_WIDTH-1, delta + ROUND_H, ROUND_W, ROUND_H);
  910.             /* draw border on card */
  911.             XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, 
  912.             CARD_WIDTH-1, delta + ROUND_H, ROUND_W, ROUND_H);
  913.         } else    
  914. #endif
  915.         {
  916.             /* fill the background */
  917.             XFillRectangle(dpy, d, whitegc, x, y, 
  918.                     CARD_WIDTH-1, delta);
  919.             /* draw border on card */
  920.             XDrawRectangle(dpy, d, blackgc, x, y, 
  921.                     CARD_WIDTH-1, delta);
  922.         }
  923.         card_is_clipped = True;
  924.     } else    {    /* fill all the card */
  925. #ifndef NO_ROUND_CARDS
  926.         if (ROUND_W)    {
  927.             /* fill the background */
  928.             XmuFillRoundedRectangle(dpy, d, whitegc, x, y, 
  929.             CARD_WIDTH-1, CARD_HEIGHT-1,
  930.             ROUND_W, ROUND_H);
  931.             /* draw border on card */
  932.             XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, 
  933.             CARD_WIDTH-1, CARD_HEIGHT-1,
  934.             ROUND_W, ROUND_H);
  935.         } else
  936. #endif
  937.         {
  938.             /* fill the background */
  939.             XFillRectangle(dpy, d, whitegc, x, y, 
  940.             CARD_WIDTH-1, CARD_HEIGHT-1);
  941.             /* draw border on card */
  942.             XDrawRectangle(dpy, d, blackgc, x, y, 
  943.             CARD_WIDTH-1, CARD_HEIGHT-1);
  944.         }
  945.         card_is_clipped = False;
  946.     }
  947.  
  948.     switch (rank)    {
  949.     case    King:
  950.         draw_king(suit, x, y, d);
  951.         break;
  952.     case    Queen:
  953.         draw_queen(suit, x, y, d);
  954.         break;
  955.     case    Jack:
  956.         draw_jack(suit, x, y, d);
  957.         break;
  958.  
  959.     case    Ten:
  960.         draw_pip(suit, MID_CARD_X + x, CARD_TEN_Y1 + y, d);
  961.         draw_did(suit, MID_CARD_X + x, CARD_TEN_Y2 + y, d);
  962.         draw_eight_pips(suit, x, y, d);
  963.         break;
  964.  
  965.     case    Nine:
  966.         draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d);
  967.         draw_eight_pips(suit, x, y, d);
  968.         break;
  969.  
  970.     case    Eight:
  971.         draw_did(suit, x + MID_CARD_X, y + CARD_EIGHT_Y, d);
  972.         /* fall thru */
  973.     case    Seven:
  974.         draw_pip(suit, MID_CARD_X + x, CARD_SEVEN_Y + y, d);
  975.         /* fall thru */
  976.     case    Six:
  977.         draw_six_pips(suit, x, y, d);
  978.         break;
  979.  
  980.     case    Five:
  981.         draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d);
  982.         /* fall thru */
  983.     case    Four:
  984.         draw_four_pips(suit, x, y, d);
  985.         break;
  986.  
  987.     case    Three:
  988.         draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d);
  989.         /* fall thru */
  990.     case    Deuce:
  991.         draw_two_pips(suit, x, y, d);
  992.         break;
  993.         case    13:
  994.     case    Ace:
  995.         draw_center_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d);
  996.         break;
  997.     default:
  998.         assert(0);
  999.     }
  1000.  
  1001.         if (rank != 13)
  1002.         draw_rank(x, y, rank, suit, d);
  1003.  
  1004.     /* clear the clip mask */
  1005.     XSetClipMask(dpy, cardgc, None);
  1006.  
  1007. #ifndef NO_ROUND_CARDS
  1008.     if (ROUND_W) {
  1009.         if (!delta && !x &&!y) {
  1010.         /* special: if round card and initial call, repaint rounding */
  1011.         /* this is for extremely rounded card which get over-painted */
  1012.         XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, 
  1013.             CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  1014.         }
  1015.         XSetClipMask(dpy, whitegc, None);
  1016.         if (cardgc != blackgc)
  1017.         XSetClipMask(dpy, blackgc, None);
  1018.     }
  1019. #endif
  1020. }
  1021.  
  1022. #ifdef LOADCARDS
  1023. static void paint_external_card(int x, int y, int cardnumber, int delta) {
  1024.     if (cardnumber == CARDBACK)
  1025.     cardgc = backgc;
  1026.     else if (SUIT(cardnumber) == Spade || SUIT(cardnumber) == Club) {
  1027.     cardgc = graphic.is_color ? blackgc: whitegc;
  1028.     } else {
  1029.     cardgc = redgc;
  1030.     }
  1031.     if (delta && !ROUND_W) {
  1032.     cliprects[0].height = delta;
  1033.     XSetClipRectangles(dpy, cardgc, x, y, cliprects, 1, Unsorted);
  1034.     if (inset)
  1035.         XSetClipRectangles(dpy, blackgc, x, y, cliprects, 1, Unsorted);
  1036.     }
  1037.  
  1038. #ifndef NO_ROUND_CARDS
  1039.     if (ROUND_W) {
  1040.     XSetClipMask(dpy, cardgc, cardclipmap);
  1041.     XSetClipOrigin(dpy, cardgc, x, y);
  1042.     if (inset) {
  1043.         XSetClipMask(dpy, blackgc, cardclipmap);
  1044.         XSetClipOrigin(dpy, blackgc, x, y);
  1045.     }
  1046.     }
  1047. #endif
  1048.  
  1049.     XCopyPlane(dpy, card_bitmaps[cardnumber], table, cardgc, 0, 0, 
  1050.     CARD_WIDTH-2*inset, CARD_HEIGHT-2*inset, x+inset, y+inset, 1);
  1051.  
  1052.     if (inset) {    /* must draw border */
  1053. #ifndef NO_ROUND_CARDS
  1054.         if (ROUND_W)
  1055.           XmuDrawRoundedRectangle(dpy, table, blackgc, x, y, 
  1056.         CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  1057.     else
  1058. #endif
  1059.         XDrawRectangle(dpy, table, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1);
  1060.     }
  1061.  
  1062.     if (delta || ROUND_W) {
  1063.     XSetClipMask(dpy, cardgc, None);
  1064.     if (inset)
  1065.         XSetClipMask(dpy, blackgc, None);
  1066.     }
  1067. }
  1068. #endif
  1069.  
  1070.  
  1071. void PaintCard(int x, int y, int c, int delta) {
  1072.     static Suit Suittab[4] = { Club, Spade, Heart, Diamond };
  1073.     static int initial_call = 1;   /* initial-call-flag */
  1074.  
  1075.  
  1076.     /* JOKERs not yet fully implemented */
  1077.     if (c == NOTHING)
  1078.     return;
  1079.     
  1080.     if (c != OUTLINE) {
  1081. #ifdef LOADCARDS
  1082.     if (card.cardset) {    /* externally loaded cards: */
  1083.         if (IS_JOKER(c))
  1084.         c = SUIT(c) + SUITSYMBOL;    /* do this instead */
  1085.         if (c < numcards) {
  1086.         paint_external_card(x, y, c, delta);
  1087.         return;
  1088.         } else if (c == CARDBACK) {
  1089.         paint_cardback(x, y, delta, table);
  1090.         return;
  1091.         } else {    /* must be suit symbol */
  1092.         c = OUTLINE;    /* do outline as replacement */
  1093.         /* and fall thru */
  1094.         }
  1095.     } else
  1096. #endif
  1097.     {            /* do default cards */
  1098.         if (!mem_option) {
  1099.         if (IS_JOKER(c))
  1100.             paint_joker(x, y, table);    /* do this instead */
  1101.         else if (c != CARDBACK)
  1102.             paint_large_card(x, y, RANK(c), Suittab[SUIT(c)], delta, table);
  1103.         else {
  1104.             if (!delta)
  1105.             delta = CARD_HEIGHT;
  1106.             paint_cardback(x, y, delta, table);
  1107.         }
  1108.         return;
  1109.         } else {
  1110.         if (initial_call) {
  1111.             int i;
  1112.             initial_call = 0;
  1113.             cardpicts[57] = 0;    /* Joker is loaded on request */
  1114.             for (i = 0; i <= 56; ++i) {
  1115.             if (xpmdir && (i < 52 || i >= 56)) {
  1116.                 char s[200];
  1117.                 if (i == CARDBACK) {
  1118.                 strcpy(s, xpmdir);
  1119.                     strcat(s, "/Cardback.xpm");
  1120.                 } else 
  1121.                 sprintf(s, "%s/%s.%s.xpm", xpmdir,
  1122.                    US_rank_name[RANK(i)], US_suit_name[SUIT(i)]);
  1123.                 if (read_pixmap(s, &cardpicts[i]))
  1124.                 continue;    /* load succeeded */
  1125.             }
  1126.             /* no file found, must create internal card */
  1127.             cardpicts[i] = XCreatePixmap(dpy, table,
  1128.                   CARD_WIDTH, CARD_HEIGHT, DefaultDepth(dpy, screen));
  1129.             if (i == CARDBACK)
  1130.                 paint_cardback(0, 0, CARD_HEIGHT, cardpicts[i]);
  1131.             else
  1132.                 paint_large_card(0, 0, RANK(i), Suittab[SUIT(i)], 0, cardpicts[i]);
  1133.             }
  1134. #ifdef SAVE_IMAGES
  1135.             for (i = 0; i < 52; ++i) {
  1136.             char s[20];
  1137.             sprintf(s, "%s.%s.xpm",
  1138.                 US_rank_name[RANK(i)], US_suit_name[SUIT(i)]);
  1139.             write_pixmap(s, cardpicts[i], cardclipmap);
  1140.             }
  1141. #endif
  1142.         }
  1143.         if (IS_JOKER(c)) {
  1144.             c = 57;
  1145.             if (!cardpicts[c]) {
  1146.             /* must load or draw joker */
  1147.             if (xpmdir) {
  1148.                 char s[200];
  1149.                 sprintf(s, "%s/Joker.xpm", xpmdir);
  1150.                 (void)read_pixmap(s, &cardpicts[c]);
  1151.             }
  1152.             if (!cardpicts[c]) {
  1153.                 cardpicts[c] = XCreatePixmap(dpy, table,
  1154.                     CARD_WIDTH, CARD_HEIGHT, DefaultDepth(dpy, screen));
  1155.                 paint_joker(0, 0, cardpicts[c]);
  1156.             }
  1157.             }
  1158.         }
  1159.         delta += ROUND_H;
  1160.         if (delta == ROUND_H || delta > CARD_HEIGHT)
  1161.             delta = CARD_HEIGHT;
  1162.         XSetClipOrigin(dpy, cardbackgc, x, y);
  1163.         XCopyArea(dpy, cardpicts[c], table, cardbackgc, 0, 0, CARD_WIDTH, delta, x, y);
  1164.         return;
  1165.         }
  1166.     }
  1167.     }
  1168.  
  1169.     /* if (c == OUTLINE) */
  1170.     /* to be sure the place is clear: */
  1171.     XClearArea(dpy, table, x, y, CARD_WIDTH, CARD_HEIGHT, False);
  1172. #ifndef NO_ROUND_CARDS
  1173.     if (ROUND_W)
  1174.     XmuDrawRoundedRectangle(dpy, table, blackgc, x, y,
  1175.        CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  1176.     else
  1177. #endif
  1178.     XDrawRectangle(dpy, table, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1);
  1179. }
  1180.